package com.yvon.maple.service.auth.valicode.validate.code.processor;

import com.yvon.boot.common.result.GlobalException;
import com.yvon.maple.service.auth.param.CodeParam;
import com.yvon.maple.service.auth.enums.CodeTypeEnum;
import com.yvon.maple.service.auth.valicode.validate.code.generator.CodeGenerator;
import com.yvon.maple.service.auth.valicode.validate.code.repository.CodeRepository;
import com.yvon.maple.service.auth.valicode.vo.CodeVo;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Map;
import java.util.Objects;

/**
 * 抽象的图片验证码处理器
 * @author : Yvon
 * @since 2019/5/26
 */
@Data
@AllArgsConstructor
public abstract class AbstractCodeProcessor<C extends CodeVo> implements CodeProcessor {

	/**
	 * 收集系统中所有的 {@link CodeProcessor} 接口的实现。
	 *
	 * 这是Spring开发的常见技巧，叫做定向查找（定向搜索）
	 *
	 * Spring启动时，会查找容器中所有的ValidateCodeGenerator接口的实现，并把Bean的名字作为key，放到map中
	 * 在我们这个系统中，ValidateCodeGenerator接口有两个实现，一个是ImageCodeGenerator，一个是SmsCodeGenerator，系统启动完成后，这个map中就会有2个bean，key分别是bean的名字
	 *
	 * 生成验证码的时候，会根据请求的不同（有一个type值区分是获取短信验证码还是图片验证码），来获取短信验证码的生成器或者图形验证码的生成器
	 */
	@Autowired
	private Map<String, CodeGenerator> generatorPool;


	@Autowired
	private CodeRepository codeRepository;


	@Override
	public C create(CodeParam param) {
		// 生成
		C validateCode = generate(param);
		validateCode.setGrantType(param.getValidateType());
		// 保存
		save(validateCode);
		// 发送
		send(validateCode);

		validateCode.setCode(null);

		return validateCode;
	}

	/**
	 * 生成校验码
	 *
	 * @param param 请求参数
	 * @return {@link C }
	 * @author : Yvon / 2021-08-25
	 */
	@SuppressWarnings("unchecked")
	private C generate(CodeParam param) {
		CodeGenerator generator = getGenerator(param.getValidateType());
		return (C) generator.generate(param);
	}

	public CodeGenerator getGenerator(String grantType) {
		CodeTypeEnum codeTypeEnum = CodeTypeEnum.getByType(grantType);
		if (Objects.isNull(codeTypeEnum)) {
			throw new GlobalException("grantType 不支持，请传递正确的 grantType 参数");
		}
		CodeGenerator codeGenerator = generatorPool.get(codeTypeEnum.getGenerator());
		if (codeGenerator == null) {
			throw new GlobalException("grantType 不支持，请传递正确的 grantType 参数");
		}
		return codeGenerator;
	}

	/**
	 * 保存校验码
	 *
	 * @param validateCode
	 */
	private void save(C validateCode) {
		CodeVo code = new CodeVo(validateCode.getCode(), validateCode.getExpire(), validateCode.getKey(), validateCode.getGrantType());
		codeRepository.save(code);
	}

	/**
	 * 发送校验码，由子类实现
	 *
	 * @param validateCode
	 * @author : Yvon / 2021-08-25
	 */
	protected abstract void send(C validateCode);

	/**
	 * 根据请求的url获取校验码的类型
	 * @return
	 */
//	private CodeType getValidateCodeType() {
//		String type = StrUtil.subBefore(getClass().getSimpleName(), "CodeProcessor", false);
//		return CodeType.valueOf(type.toUpperCase());
//	}


}
